package cn.topevery.garden.dal.logic;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.hutool.core.bean.BeanUtil;
import cn.topevery.garden.dal.dao.ExtentDao;
import cn.topevery.garden.dal.dao.FacilitiesClassDao;
import cn.topevery.garden.dal.dao.FacilitiesDao;
import cn.topevery.garden.dal.util.GeometryExtHelper;
import cn.topevery.garden.entity.dto.FacilitiesDTO;
import cn.topevery.garden.entity.po.*;
import cn.topevery.garden.entity.query.FacilitiesQuery;
import cn.topevery.garden.entity.vo.FacilitiesPageVO;
import cn.topevery.garden.entity.vo.FacilitiesPoiVO;
import cn.topevery.garden.entity.vo.FacilitiesVO;
import cn.topevery.garden.entity.vo.oneMap.CountVO;
import cn.topevery.garden.framework.base.BaseLogic;
import com.github.dozermapper.core.Mapper;
import hw.topevery.basis.entity.po.SysUser;
import hw.topevery.framework.GeometryHelper;
import hw.topevery.framework.db.base.BaseEntityDao;
import hw.topevery.framework.db.entity.DataPager;
import hw.topevery.framework.entity.KeyValue;
import hw.topevery.framework.enums.GeometryTypeEnum;
import hw.topevery.framework.web.JsonResult;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @author code-generate
 * @date 2021-08-06
 */
@Service
public class FacilitiesLogic extends BaseLogic<Facilities> {
    @Autowired
    FacilitiesDao facilitiesDao;

    @Autowired
    private Mapper mapper;

    @Autowired
    private FacilitiesFileLogic fileLogic;

    @Override
    public BaseEntityDao<Facilities, Integer> getDao() {
        return facilitiesDao;
    }


    /**
     * 获取列表
     *
     * @param query
     */
    public DataPager<FacilitiesPageVO> listPage(FacilitiesQuery query) {
        return facilitiesDao.listPage(query);
    }

    /**
     * 根据自增id批量删除
     *
     * @param ids
     */
    public void deleteBatchById(String userId, Integer[] ids) {
        facilitiesDao.delete(userId, ids);
    }

    @Transactional
    public void saveInfo(String userId, FacilitiesDTO dto) {
        Facilities facilities = mapper.map(dto, Facilities.class);
        if (dto.getMapRangesPoints().size() > 0) {
            String Wkt = "";
            switch (dto.getGeomType()) {
                case 0:
                    Wkt = GeometryHelper.getWellKnownText(dto.getMapRangesPoints(), GeometryTypeEnum.POINT);
                    break;
                case 1:
                    Wkt = GeometryHelper.getWellKnownText(dto.getMapRangesPoints(), GeometryTypeEnum.LINE);
                    break;
                case 2:
                    Wkt = GeometryHelper.getWellKnownText(dto.getMapRangesPoints(), GeometryTypeEnum.PLANE);
                    break;
            }
            facilities.geom = GeometryHelper.getGeometry(Wkt);
        }
        facilitiesDao.saveOrUpdate(userId, facilities);
        if (dto.getId() != null) {
            fileLogic.delByMainId(userId, dto.getId());
        }
        if (dto.getFileList() != null && !dto.getFileList().isEmpty()) {
            for (FacilitiesFile file : dto.getFileList()) {
                file.setMainId(facilities.getId());
                file.setDbLastUpdateDate(LocalDateTime.now());
                fileLogic.saveOrUpdate(userId, file);
            }
        }
    }

    public FacilitiesVO getById(Integer id) {
        Facilities entity = facilitiesDao.getEntity(id);
        FacilitiesVO vo = mapper.map(entity, FacilitiesVO.class);
        if (entity.geom != null) {
            vo.setMapRangesPoints(GeometryHelper.convertGeometryToPoint(entity.geom));
        }
        return vo;
    }

    public FacilitiesVO getByCodeAndType(String code, Integer type) {
        Facilities entity = facilitiesDao.getByCodeAndType(code, type);
        if (entity == null) {
            return null;
        }
        FacilitiesVO vo = mapper.map(entity, FacilitiesVO.class);
        if (entity.geom != null) {
            vo.setMapRangesPoints(GeometryHelper.convertGeometryToPoint(entity.geom));
        }
        return vo;
    }

    /**
     * 描述 获取统计数量.
     *
     * @param name     the name
     * @param extentId the extent id
     * @return the list
     * @author wenzhao.lin
     * @created 2021 -08-25 09:26:38 Get count list.
     */
    public Map getCount(String name, Integer extentId, String typeId) {
        return facilitiesDao.getCount(name, extentId, typeId);
    }

    /**
     * 描述 通过类型获取列表
     *
     * @param name     the name
     * @param extentId the extent id
     * @param type     the type
     * @return the person list by type
     * @author wenzhao.lin
     * @created 2021 -08-25 09:26:38
     */
    public List<Facilities> getFacilitiesListByType(String name, Integer extentId, String type) {
        List<Facilities> list = facilitiesDao.getFacilitiesListByType(name, extentId, type);
        for (Facilities facilities : list) {
            if (facilities.getGeom() != null) {
                facilities.setMapRangesPoints(GeometryHelper.convertGeometryToPoint(facilities.getGeom()));
                facilities.setGeom(null);
            }
        }

        return list;
    }

    /**
     * 描述 通过类型获取poi列表
     *
     * @return the person list by type
     * @author wenzhao.lin
     * @created 2021 -08-25 09:26:38
     */
    public List<FacilitiesPoiVO> getFacilitiesPoiListByType(FacilitiesQuery query) {
        List<FacilitiesPoiVO> list = facilitiesDao.getFacilitiesPoiListByType(query);
        for (FacilitiesPoiVO facilities : list) {
            if (facilities.getGeom() != null) {
                facilities.setMapRangesPoints(GeometryHelper.convertGeometryToPoint(facilities.getGeom()));
                facilities.setGeom(null);
            }
        }

        return list;
    }

    /**
     * 描述 获取类型列表
     *
     * @param name     the name
     * @param extentId the extent id
     * @return the person type list
     * @author wenzhao.lin
     * @created 2021 -08-27 09:22:09
     */
    public List<Facilities> getTypeList(String name, Integer extentId) {
        return facilitiesDao.getTypeList(name, extentId);
    }

    /**
     * 描述 一张图管理 - 获取设施统计数量.
     *
     * @return the list
     * @author wenzhao.lin
     * @created 2021 -09-07 16:55:35 Get type count list.
     */
    public List<CountVO> getTypeCount() {
        return facilitiesDao.getTypeCount();
    }

    public List<Map<String, Object>> facilitiesCount() {
        return facilitiesDao.facilitiesCount();
    }

    @Autowired
    private ParkLogic parkLogic;
    @Autowired
    private ExtentDao extentDao;
    @Autowired
    private FacilitiesClassDao facilitiesClassDao;

    public JsonResult<?> analysisExcel(MultipartFile file, SysUser user) {
        ImportParams importParams = new ImportParams() {{
            setHeadRows(1);
            setNeedVerify(true);
        }};
        ExcelImportResult<FacilitiesVO> result;
        try {
            result = ExcelImportUtil.importExcelMore(file.getInputStream(), FacilitiesVO.class, importParams);
        } catch (Exception e) {
            e.printStackTrace();
            return JsonResult.error("解析发生错误，请按照模板格式填写数据！");
        }
        // 解析正常，继续校验详细数据
        List<FacilitiesVO> parsePassList = result.getList();
        List<FacilitiesVO> parseFailList = result.getFailList();
        //对公园和片区数据进行校验
        CompletableFuture<List<Park>> parkFuture = CompletableFuture.supplyAsync(() -> parkLogic.getShortList().stream().map(m -> BeanUtil.toBean(m, Park.class)).collect(Collectors.toList()));
        CompletableFuture<List<Extent>> extentFuture = CompletableFuture.supplyAsync(() -> extentDao.getListEntityByColumns(Collections.singletonList(new KeyValue("c_db_status", 0))));
        CompletableFuture<List<FacilitiesClass>> facilitiesFuture = CompletableFuture.supplyAsync(() -> facilitiesClassDao.getListEntityByColumns(new ArrayList<KeyValue>(2) {{
            add(new KeyValue("c_db_status", 0));
            add(new KeyValue("c_parent_id", "33b795d3-a5f8-48d6-a03b-fef0047d0128"));
        }}));
        List<Park> parkList = null;
        List<Extent> extentList = null;
        List<FacilitiesClass> facilitiesClassList = null;
        try {
            parkList = parkFuture.get();
            extentList = extentFuture.get();
            facilitiesClassList = facilitiesFuture.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        final List<Park> finalParkList = parkList;
        final List<Extent> finalExtentList = extentList;
        final List<FacilitiesClass> finalFacilitiesClassList = facilitiesClassList;
        List<FacilitiesVO> verifyFailList = parsePassList.stream().filter(f -> {
            boolean flag = false;
            if (StringUtils.isNotBlank(f.getParkName())) {
                List<Park> parks = finalParkList.stream().filter(park -> park.name.equals(f.getParkName())).collect(Collectors.toList());
                flag = CollectionUtils.isEmpty(parks);
                if (!flag) f.setParkId(parks.get(0).getId());
                if (StringUtils.isNotBlank(f.getExtentName()) && !flag) {
                    List<Extent> extents = finalExtentList.stream().filter(e -> Objects.equals(e.getParkId(), parks.get(0).getId())).collect(Collectors.toList());
                    flag = CollectionUtils.isEmpty(extents);
                    if (!flag) f.setExtentId(extents.get(0).getId());
                }
            }
            if (!flag && StringUtils.isNotBlank(f.getTypeName())) {
                List<FacilitiesClass> facilitiesClasses = finalFacilitiesClassList.stream().filter(clazz -> f.getTypeName().equals(clazz.getName())).collect(Collectors.toList());
                flag = CollectionUtils.isEmpty(facilitiesClasses);
                if (!flag) {
                    FacilitiesClass facilitiesClass = facilitiesClasses.get(0);
                    f.setTypeId(facilitiesClass.getEntityId());
                    f.setGeomType(facilitiesClass.getGeomType());
                }
            }
            return flag;
        }).collect(Collectors.toList());
        parsePassList.removeAll(verifyFailList);
        parseFailList.addAll(verifyFailList);
        new Thread(() -> {
            //导入校验成功的数据
            List<Facilities> facilitiesList = parsePassList.stream().map(vo -> BeanUtil.copyProperties(vo, Facilities.class)).collect(Collectors.toList());
            facilitiesDao.insert(user.id.toString(), facilitiesList);
        }).start();
        parsePassList.forEach(facilitiesVO -> facilitiesVO.setIsPass(true));
        parseFailList.forEach(facilitiesVO -> facilitiesVO.setIsPass(false));
        //将失败的条目也导入作为结果返回
        parsePassList.addAll(parseFailList);
        Map<String, Object> res = new HashMap<>(2);
        res.put("isPass", parseFailList.size() == 0 && parsePassList.size() > 0);
        res.put("data", parsePassList);
        return JsonResult.ok(res);
    }
}
